'use strict';

let util = require('util');
let Fiber = require('fibers');
let outputLogger = require('../modules/lib/loggers').output;
let models = require('../modules/models');
let School = models.School;
let SchoolDao = models.SchoolDao;
let RawAttendanceDao = models.RawAttendanceDao;
let AttendanceValueDao = models.AttendanceValueDao;

let attendanceService = require('../modules/services/attendance');
let AttendanceStatus = models.AttendanceStatus;

let SchoolCheckedMap = {
};

function main() {
    let schools = SchoolDao.find({});

    // 每天重置
    resetSchoolCheckedMap(schools);
    setInterval(function() {
        Fiber(function() {
            resetSchoolCheckedMap(schools);
        }).run();
    }, 1000 * 60 * 60 * 24);

    // Timer
    setInterval(function() {
        Fiber(function() {
            outputLogger.info('检查状态');
            filterSchoolsToCheck(schools)
                .forEach(checkSchool);
        }).run();
    }, 1000 * 60);
    //filterSchoolsToCheck(schools)
    //    .forEach(checkSchool);
}

function resetSchoolCheckedMap(schools) {
    schools.forEach(school => {
        SchoolCheckedMap[school.id] = [{
            enterStatus: false,
            exitStatus: false
        }, {
            enterStatus: false,
            exitStatus: false
        }, {
            enterStatus: false,
            exitStatus: false
        }];
    });
}

function filterSchoolsToCheck(schools) {
    return schools.map(school => {
        let checkTimes = getCheckTimesToday(school.checkTimeSet);
        let checkStatus = getCheckStatusNow(school, checkTimes)
        if ( !checkStatus ) {
            return null;
        }

        return {
            school: school,
            checkTime: checkStatus.checkTime,
            checkTimeIndex: checkStatus.checkTimeIndex,
            status: checkStatus.status
        };
    }).filter(schoolRecord => schoolRecord != null);
}

function checkSchool(schoolRecord) {
    let school = schoolRecord.school;
    let checkTime = schoolRecord.checkTime;
    let checkTimeIndex = schoolRecord.checkTimeIndex;
    let statusName = schoolRecord.status;

    if ( statusName == 'enterStatus' ) {
        checkSchoolEnterStatus(school, checkTime, checkTimeIndex);
    }
    else if ( statusName == 'exitStatus' ) {
        checkSchoolExitStatus(school, checkTime, checkTimeIndex);
    }
    
    SchoolCheckedMap[school.id][checkTimeIndex][statusName] = true;
}

function checkSchoolEnterStatus(school, checkTime, checkTimeIndex) {
    school.grades.forEach(grade => {
        grade.natureClasses.forEach(natureClass => {
            natureClass.students.forEach(student => {
                checkStudentEnterStatus(student, checkTime, checkTimeIndex);
            });
        });
    });
}

function checkStudentEnterStatus(student, checkTime, checkTimeIndex) {
    let attendance = attendanceService.getAttendanceOfStudentToday(student);
    let attendanceValue = attendance.values[checkTimeIndex];
    let statusDescription = '无';

    // 检查是否在校，在校即出勤
    if ( student.atSchool ) {
        attendanceValue.enterStatus = AttendanceStatus.Attended;
        statusDescription = '出勤';
    }
    // 不在校则设定为迟到
    else {
        attendanceValue.enterStatus = AttendanceStatus.Late;
        statusDescription = '迟到';
    }

    outputLogger.info(`入校检查：${student.name}, ${statusDescription}`);
    AttendanceValueDao.update(attendanceValue);
}

function checkSchoolExitStatus(school, checkTime, checkTimeIndex) {
    school.grades.forEach(grade => {
        grade.natureClasses.forEach(natureClass => {
            natureClass.students.forEach(student => {
                checkStudentExitStatus(student, checkTime, checkTimeIndex);
            });
        });
    });
}

function checkStudentExitStatus(student, checkTime, checkTimeIndex) {
    let attendance = attendanceService.getAttendanceOfStudentToday(student);
    let attendanceValue = attendance.values[checkTimeIndex];
    let statusDescription = '无';

    // 检查是否在校，在校即出勤
    if ( student.atSchool ) {
        attendanceValue.exitStatus = AttendanceStatus.Attended;
        statusDescription = '出勤';

        outputLogger.info(`出校检查：${student.name}, ${statusDescription}`);
        AttendanceValueDao.update(attendanceValue);

        return;
    }
    
    // 如果不在校
    // 扫描在进入时间和退出时间之内的记录
    let now = new Date();
    let startTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 
            checkTime.startHour, checkTime.startMinute);
    let endTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 
            checkTime.endHour, checkTime.endMinute);

    // 如果有进出，则早退
    let rawAttendances = RawAttendanceDao.find({
        student: student.id,
        time: {
            $gte: startTime,
            $lte: endTime
        }
    });

    if ( rawAttendances.length ) {
        attendanceValue.exitStatus = AttendanceStatus.Early;
        statusDescription = '早退';
    }
    // 否则都设置为旷课
    else {
        attendanceValue.enterStatus = AttendanceStatus.Absent;
        attendanceValue.exitStatus = AttendanceStatus.Absent;
        statusDescription = '旷课';
    }

    outputLogger.info(`出校检查：${student.name}, ${statusDescription}`);
    AttendanceValueDao.update(attendanceValue);
}

function getCheckTimesToday(checkTimeSet) {
    let now = new Date();

    if ( now.getDay() == 0 ) {
        return checkTimeSet.sunday;
    }
    else if ( now.getDay() == 6 ) {
        return checkTimeSet.saturday;
    }
    else {
        return checkTimeSet.weekdays;
    }
}

function getCheckStatusNow(school, checkTimes) {
    let now = new Date();
    let nowMinutes = toMinutes(now.getHours(), now.getMinutes());

    let validStatus = checkTimes.map((checkTime, checkTimeIndex) => {
        if ( checkTime.status == 0 ) {
            return null;
        }

        if ( nowMinutes > startMinutes(checkTime) &&
            !SchoolCheckedMap[school.id][checkTimeIndex].enterStatus ) {
            return {
                checkTime: checkTime,
                checkTimeIndex: checkTimeIndex,
                status: 'enterStatus'
            }
        }

        if ( nowMinutes > endMinutes(checkTime) &&
            !SchoolCheckedMap[school.id][checkTimeIndex].exitStatus ) {
            return {
                checkTime: checkTime,
                checkTimeIndex: checkTimeIndex,
                status: 'exitStatus'
            }
        }

        return null;
    })
    .filter(checkStatus => checkStatus != null);

    if ( validStatus.length ) {
        return validStatus[0];
    }

    return null;
}

// 将小时和分钟都转换为分钟
function toMinutes(hour, minute) {
    return hour * 60 + minute;
}

function startMinutes(checkTime) {
    return toMinutes(checkTime.startHour, checkTime.startMinute);
}

function endMinutes(checkTime) {
    return toMinutes(checkTime.endHour, checkTime.endMinute);
}

Fiber(main).run();
